home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Texteditors / XDME / Src / search.c < prev    next >
C/C++ Source or Header  |  1996-09-26  |  11KB  |  479 lines

  1. /******************************************************************************
  2.  
  3.     MODUL
  4.     search.c
  5.  
  6.     DESCRIPTION
  7.     Inherits all the search/replace stuff for DME
  8.  
  9.     NOTES
  10.  
  11.     BUGS
  12.  
  13.     TODO
  14.  
  15.     EXAMPLES
  16.  
  17.     SEE ALSO
  18.  
  19.     INDEX
  20.  
  21.     HISTORY
  22.     28. May 1992    ada created
  23.  
  24. ******************************************************************************/
  25.  
  26. /* Includes */
  27. #include "defs.h"
  28. #define MYDEBUG     0
  29. #include <debug.h>
  30.  
  31. /* Globale Variable */
  32.  
  33. /* Interne Defines & Strukturen */
  34.  
  35. /* Interne Variable */
  36. /*static*/ UBYTE Fstr[MAXLINELEN]; /* PATCH_NULL - commented out for spcvars */
  37. /*static*/ UBYTE Rstr[MAXLINELEN]; /* PATCH_NULL - commented out for spcvars */
  38. static char Srch_sign;
  39. static char Doreplace;
  40.  
  41. /* Interne Prototypes */
  42. Prototype void do_findstr    (void);
  43. Prototype void do_findr     (void);
  44. Prototype void do_find        (void);
  45. Prototype void do_replace    (void);
  46. Prototype void search_operation (void);
  47.  
  48.  
  49. /*****************************************************************************
  50.  
  51.     NAME
  52.     do_findstr
  53.  
  54.     PARAMETER
  55.     av[0]        "find" or "replace"
  56.     av[1]        string to find or replace-string
  57.  
  58.     DESCRIPTION
  59.     Copies the search/replace-string to the internal buffer.
  60.  
  61. ******************************************************************************/
  62.  
  63. void do_findstr (void)
  64. {
  65.     if (av[0][0] == 'f')    /* Check command name */
  66.     strcpy(Fstr, av[1]);    /* "find" */
  67.     else
  68.     strcpy(Rstr, av[1]);    /* "replace" */
  69. } /* do_findstr */
  70.  
  71.  
  72. /*****************************************************************************
  73.  
  74.     NAME
  75.     do_findr
  76.  
  77.     PARAMETER
  78.     av[0]    "findr", "nextr" or "prevr"
  79.     av[1]    find-string
  80.     av[2]    replace-string
  81.  
  82.     DESCRIPTION
  83.     Starts one find/replace-operation with both search- and replace-string
  84.     as arguments.
  85.  
  86. ******************************************************************************/
  87.  
  88. void do_findr (void)
  89. {
  90.     Doreplace = 1;  /* Really replace */
  91.     Srch_sign = 1;  /* Search to EOF */
  92.  
  93.     switch (*av[0])
  94.     {
  95.     case 'f':
  96.         strcpy(Fstr, av[1]);    /* Set strings for "findr" */
  97.         strcpy(Rstr, av[2]);
  98.         break;
  99.  
  100.     case 'p':
  101.         Srch_sign = -1;        /* Search reverse */
  102.         break;
  103.     }
  104.  
  105.     search_operation(); /* Start search */
  106. } /* do_findr */
  107.  
  108.  
  109. /*****************************************************************************
  110.  
  111.     NAME
  112.     do_find
  113.  
  114.     PARAMETER
  115.     av[0]    "find", "next" or "prev"
  116.     av[1]    find-string if av[0] == find
  117.  
  118.     DESCRIPTION
  119.     Looks for a new string or searches forwards/backwars for the old one.
  120.  
  121. ******************************************************************************/
  122.  
  123. void do_find (void)
  124. {
  125.     Doreplace = 0;  /* Don't replace */
  126.     Srch_sign = 1;
  127.  
  128.     switch(av[0][0])
  129.     {
  130.     case 'f':   /* Find: new string */
  131.         strcpy(Fstr, av[1]);
  132.     break;
  133.  
  134.     case 'p':   /* Search reverse */
  135.         Srch_sign = -1;
  136.     break;
  137.     }
  138.  
  139.     search_operation ();
  140. } /* do_find */
  141.  
  142.  
  143. /*****************************************************************************
  144.  
  145.     NAME
  146.     do_replace
  147.  
  148.     PARAMETER
  149.     av[0]    "replace"
  150.  
  151.     DESCRIPTION
  152.     Substitutes the next strlen(search-string) chars with the rep-string.
  153.     This command does no checking ! It always removes strlen(search-
  154.     string) chars and the rep-string is always inserted.
  155.  
  156. ******************************************************************************/
  157.  
  158. void do_replace (void)
  159. {
  160.     ULONG  rlen;
  161.     ULONG  flen;
  162.     Column col;
  163.  
  164.     rlen = strlen (Rstr);
  165.     flen = strlen (Fstr);
  166.  
  167.     text_sync ();
  168.  
  169.     col = Ep->column;
  170.  
  171.     /* Check whether replace-string does fit into the line */
  172.     if (rlen > flen && (Clen+rlen-flen) > MAXLINELEN-1)
  173.     {
  174.     error ("replace:\nLine Too Long");
  175.     } else
  176.     /* This checks whether the search-pattern does fit into
  177.     the current line at the current position !?!?! */
  178.        if (Clen >= col+flen)
  179.     {
  180.     /* Move rest of line. Make enough place for replace-string */
  181.     movmem (Current+col+flen, Current+col+rlen, Clen-col-flen+1);
  182.  
  183.     /* copy replace-string */
  184.     if (rlen)
  185.         movmem (Rstr, Current+col, rlen);
  186.  
  187.     /* correct line-length and position after symbol */
  188.     Clen       += rlen-flen;
  189.     Ep->column += rlen -1; /* one position left since we start
  190.                   at Ep->column+1 with searching */
  191.  
  192.     if (Clen < 0)
  193.         Clen = 0;
  194.  
  195.     if (Ep->column < 0)
  196.         Ep->column = 0;
  197.     }
  198.  
  199.     /* Check display, since we are not sure, whether the actual
  200.        position is visible on the screen */
  201.     if (!text_adjust (FALSE))
  202.     {
  203.     text_sync ();
  204.     text_redisplaycurrline ();
  205.     }
  206.  
  207. } /* do_replace */
  208.  
  209.  
  210. /******************************************************************************
  211.  
  212.     NAME
  213.     search_operation
  214.  
  215.     PARAMETER
  216.     Fstr        String to look for
  217.     Rstr        String to replace Fsrt with (if Doreplace != 0)
  218.     Doreplace   Replace Fstr with Rstr ?
  219.     Ep        Different fields in this structure
  220.  
  221.     DESCRIPTION
  222.     Searches in the text for Fstr and replaces it with Rstr if Doreplace is
  223.     true. If Ep->ignorecase is true, the string-search is case-insensitive
  224.     else not.
  225.  
  226.     For speed, I did replace the old function with this new one. The
  227.     routine works like Boyer-Moore search but I didn't find a good
  228.     explanation for it in books. You will find some for searching from the
  229.     beginning of a string but none if you try reverse. Sigh.
  230.  
  231. ******************************************************************************/
  232.  
  233. //#define DEBUG
  234. static UBYTE skip[256];         /* Distance for Boyer-Moore */
  235.  
  236. void search_operation (void)
  237. {
  238.     int flen = strlen(Fstr);        /* Length of Search/Replace-String */
  239. //    int rlen = strlen(Rstr);
  240.  
  241.     UBYTE * ptr;
  242.     WORD    j;        /* Counter in Search-Pattern */
  243.     WORD    col;    /* actual column */
  244.     WORD    lin;    /* actual line */
  245.     UWORD   linlen; /* length of actual line */
  246.     UWORD   test;   /* result of case(in)sensitive compare */
  247.     ED      * ep;     /* actual editor */
  248.  
  249.     if (!flen)
  250.     {             /* Error if nothing to look for. */
  251.     error ("search:\nNo find pattern");
  252.     return;
  253.     }
  254.  
  255.     /* Note that we do not check for nothing to replace, since the user may
  256.        want to erase the full pattern */
  257.  
  258.     text_sync ();                    /* Save Current */
  259.  
  260.     ep = Ep;
  261.  
  262.     col = ep->column;            /* Actual column ... */
  263.     lin = ep->line;            /* ... and line */
  264.  
  265.     /* initskip() */
  266.     memset (skip, flen, 256);       /* Normally : Skip full length */
  267.  
  268.     if (Srch_sign > 0)
  269.     {     /* Search foreward */
  270.     ptr = Fstr;
  271.  
  272.     /* Special: Skip until characters match. NOTE: Don't calc.
  273.        skip for the LAST character in Fstr */
  274.     for (j=flen-1; j>0; ptr ++, j--)
  275.     {
  276.         if (ep->config.ignorecase)
  277.         {
  278.         skip[tolower(*ptr)] = j;
  279.         skip[toupper(*ptr)] = j;
  280.         } else
  281.         skip[*ptr] = j;
  282.     }
  283.  
  284.     ptr = GETTEXT(ep,lin);          /* Get line contents ... */
  285.     linlen = strlen (ptr);          /* ... and its length */
  286.     col ++; /* Don't find it if we're already on it */
  287.  
  288.     for (; ep; )
  289.     {
  290.         for (;;)
  291.         {
  292.         /* This is the search-loop. Always remeber Boyer-Moore
  293.         begins comparing at the end and scans forward ! */
  294.         j = flen - 1;
  295.         col += flen - 1;
  296.  
  297.         /* Until reached beginning of search-string or EOL */
  298.         while (col < linlen)
  299.         {
  300.             /* if both are equal (case(in)sensitive) */
  301.             if (ep->config.ignorecase)
  302.             test = (tolower (ptr[col]) == tolower (Fstr[j]));
  303.             else
  304.             test = (ptr[col] == Fstr[j]);
  305.  
  306.             if (test)
  307.             {
  308.             if (!j) /* Full Match */
  309.                 goto found;
  310.  
  311.             col --; /* Next position */
  312.             j --;
  313.             } else
  314.             {     /* Determine skip-length */
  315.             if (flen-j >= skip[ptr[col]])
  316.                 col += flen - j;    /* length of match */
  317.             else
  318.                 col += skip[ptr[col]]; /* Adjust to char. */
  319.  
  320.             j = flen - 1;    /* Restart j */
  321.             } /* Compare */
  322.         } /* while in line */
  323.  
  324.         lin ++;
  325.  
  326.         if (lin >= ep->lines)
  327.             break;
  328.  
  329.         ptr = GETTEXT(ep,lin);      /* Contents and Length */
  330.         linlen = strlen (ptr);
  331.         col = 0;
  332.         } /* while in text */
  333.  
  334.         if (!globalflags.global_search)
  335.         break;
  336.  
  337.         if (ep = (ED *)GetSucc((struct Node *)ep))
  338.         {
  339.         lin = 0;
  340.         ptr = GETTEXT(ep,0);      /* Contents and Length */
  341.         linlen = strlen (ptr);
  342.         col = 0;
  343.         }
  344.     } /* for all editors */
  345.     } else
  346.     { /* Search backward */
  347.     /* Special: Skip until characters match. Also don't process last char */
  348.     for (j=flen-1; j>0; j--)
  349.     {
  350.         if (ep->config.ignorecase)
  351.         {
  352.         skip[tolower(Fstr[j])] = j;
  353.         skip[toupper(Fstr[j])] = j;
  354.         } else
  355.         {
  356.         skip[Fstr[j]] = j;
  357.         }
  358.     }
  359.  
  360.     ptr = GETTEXT(ep,lin);          /* Get line contents ... */
  361.     linlen = strlen (ptr);          /* ... and its length */
  362.  
  363.     if (col >= linlen)  /* Beyound End-Of-Line ? */
  364.         col = linlen;
  365.  
  366. D(bug("new search\n"));
  367.  
  368.     for (; ep; )
  369.     {
  370.         for (;;)
  371.         {
  372.         /* Same as above but reverse */
  373.  
  374.         j = 0;
  375.         col -= flen;
  376.  
  377.         while (col >= 0)
  378.         { /* Until BOL */
  379.             /* if both are equal (case(in)sensitive) */
  380.             if (ep->config.ignorecase)
  381.             test = (tolower (ptr[col]) == tolower (Fstr[j]));
  382.             else
  383.             test = (ptr[col] == Fstr[j]);
  384.  
  385. D(bug("[%s]\n[%s]\ncol %2ld j %2ld skip %2ld\n", ptr+col, Fstr+j, col, j,
  386.         skip[ptr[col]]));
  387.  
  388.             if (test)
  389.             {
  390.             if (j == flen-1)
  391.             { /* Full Match */
  392.                 col -= flen - 1;
  393.                 goto found;
  394.             }
  395.  
  396.             col ++; /* Next position */
  397.             j ++;
  398.             } else
  399.             {     /* Determine skip-length */
  400.             j += j;
  401.  
  402.             if (j >= skip[ptr[col]])
  403.             {
  404.                 col -= j;     /* Skip back j chars to beginning of
  405.                         search and j chars to next start */
  406.             } else
  407.             {
  408.                 col -= skip[ptr[col]]; /* Adjust to char. */
  409.             }
  410.  
  411.             j = 0;     /* Restart j */
  412.             } /* Compare */
  413.         } /* while in line */
  414.  
  415.         /* Prev. line */
  416.         if (!lin)   /* Stop on 1. line */
  417.             break;
  418.  
  419.         lin --;
  420. D(bug("new line\n"));
  421.  
  422.         ptr = GETTEXT(ep,lin);      /* Contents and Length */
  423.         linlen = strlen (ptr);
  424.  
  425.         /* Last char. */
  426.         col = linlen;
  427.         } /* while in text */
  428.  
  429.         if (!globalflags.global_search)
  430.         break;
  431.  
  432.         if (ep = (ED *)GetPred((struct Node *)ep))
  433.         {
  434.         lin = ep->lines - 1;
  435.         ptr = GETTEXT(ep,lin);
  436.         col = linlen = strlen (ptr);
  437.         }
  438.     } /* for all editors */
  439.     } /* if foreward/backward */
  440.  
  441.     warn ("Pattern `%s' Not Found", Fstr);
  442.     globalflags.Abortcommand = 1;
  443.     return;
  444.  
  445. found:
  446.     if (ep != Ep)
  447.     {
  448.     switch_ed (ep);
  449.  
  450.     if (ep->iconmode)
  451.     {
  452.         uniconify ();
  453.     } else
  454.     {
  455.         /* Make window active */
  456.         WindowToFront (ep->win);
  457.         ActivateWindow (ep->win);
  458.  
  459.         set_window_params ();
  460.         window_title ();
  461.     }
  462.     }
  463.  
  464.     ep->line = lin;      /* Set Position */
  465.     ep->column = col;
  466.  
  467.     text_load ();        /* Copy Line into Current */
  468.  
  469.     if (Doreplace)
  470.     do_replace ();
  471.     else
  472.     text_adjust (FALSE);
  473. } /* search_operation */
  474.  
  475.  
  476. /******************************************************************************
  477. *****  ENDE search.c
  478. ******************************************************************************/
  479.